﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace CrazySname.GameClasses
{
    public class Cobra : IDesenhavel
    {

        public List<CobraParte> Partes { get; private set; }
        public List<Curva> Curvas { get; private set; }
        public Vector2 AreaDeCaminho { get; private set; }
        public Vector2 Inicio { get; private set; }
        public Texture2D CorpoTextura { get; set; }
        public event Action FimDeJogo;

        public Cobra()
        {
            Curvas = new List<Curva>();
        }

        public Cobra(float x, float y, Texture2D textura)
            : this()
        {
            Inicio = new Vector2(x, y);
            CorpoTextura = textura;
        }

        public void IniciaCobra()
        {
            Partes = new List<CobraParte>
                         {
                             new CobraParte(1, 0, true, CorpoTextura),
                             new CobraParte(2, 0, false, CorpoTextura),
                             new CobraParte(3, 0, false, CorpoTextura),
                             new CobraParte(4, 0, false, CorpoTextura),
                             new CobraParte(5, 0, false, CorpoTextura)
                         };
        }

        public void SetarAreaDeCaminho(float altura, float largura)
        {
            AreaDeCaminho = new Vector2(largura, altura);
        }

        public void Desenhar(SpriteBatch spriteBatch)
        {
            foreach (var parte in Partes)
            {
                var posicao = Inicio + new Vector2(parte.Posicao.X * Utilitarios.Const, parte.Posicao.Y * Utilitarios.Const);
                spriteBatch.Draw(parte.Textura, posicao, Color.White);
            }
        }

        public void AtualizaMovimento(Keys lastKeyPressed, Utilitarios gameUtilitarios)
        {
            if (Curvas.Count == 0)
            {
                var curva = new Curva(lastKeyPressed, Partes[0].Posicao);
                Curvas.Add(curva);
            }
            else if (Curvas.Last().Movimento != lastKeyPressed)
            {
                var CurvaPermitida = !((Curvas.Last().Movimento == Keys.Up && lastKeyPressed == Keys.Down) || (Curvas.Last().Movimento == Keys.Down && lastKeyPressed == Keys.Up) ||
                                       (Curvas.Last().Movimento == Keys.Left && lastKeyPressed == Keys.Right) || (Curvas.Last().Movimento == Keys.Right && lastKeyPressed == Keys.Left));
                if (CurvaPermitida)
                {
                    var curva = new Curva(lastKeyPressed, Partes[0].Posicao);
                    Curvas.Add(curva);
                }
            }
            foreach (var parte in Partes)
            {
                if (parte.EhCabeca)
                {
                    AplicaMovimentoNaCabeca(Curvas[Curvas.Count - 1].Movimento, parte);
                    parte.UltimaCurva = Curvas.Count - 1;
                }
                else
                {
                    if (Curvas.Count == 1)
                        AplicaMovimento(parte, 0);
                    else if (Curvas.Count > parte.UltimaCurva + 1 && Curvas[parte.UltimaCurva + 1].Ponto == parte.Posicao)
                        AplicaMovimento(parte, ++parte.UltimaCurva);
                    else
                        AplicaMovimento(parte, parte.UltimaCurva);
                }
                var posicao = Inicio + new Vector2(parte.Posicao.X * Utilitarios.Const, parte.Posicao.Y * Utilitarios.Const);
                if ((posicao.Y > AreaDeCaminho.Y || posicao.Y < 0) || (posicao.X > AreaDeCaminho.X || posicao.X < 0) || CobraEncostouEmSiPropria(parte))
                    FimDeJogo.Invoke();
            }
        }

        public bool CobraComeuAlimento(Alimento alimento, Utilitarios gameUtilitarios)
        {
            return alimento.Posicao == Partes[0].Posicao;
        }

        private bool CobraEncostouEmSiPropria(CobraParte parte)
        {
            var contador = Partes.Where(part => !part.EhCabeca).Where(cobraParte => !parte.Equals(cobraParte)).Count(cobraParte1 => cobraParte1.Posicao == parte.Posicao);

            return contador > 0;
        }

        private void AplicaMovimentoNaCabeca(Keys direcao, CobraParte parte)
        {
            switch (direcao)
            {
                case Keys.Down:
                    parte.MoverParaBaixo();
                    break;
                case Keys.Up:
                    parte.MoverParaCima();
                    break;
                case Keys.Right:
                    parte.MoverParaDireita();
                    break;
                case Keys.Left:
                    parte.MoverParaEsquerda();
                    break;
            }
        }

        private void AplicaMovimento(CobraParte parte, int posicao)
        {
            switch (Curvas[posicao].Movimento)
            {
                case Keys.Down:
                    parte.MoverParaBaixo();
                    break;
                case Keys.Up:
                    parte.MoverParaCima();
                    break;
                case Keys.Right:
                    parte.MoverParaDireita();
                    break;
                case Keys.Left:
                    parte.MoverParaEsquerda();
                    break;
            }
        }

        public void AdicionaParte(CobraParte cobraParte)
        {
            var posicao = new Vector2(cobraParte.Posicao.X, cobraParte.Posicao.Y);
            switch (Curvas[cobraParte.UltimaCurva].Movimento)
            {
                case Keys.Up:
                    posicao = new Vector2(cobraParte.Posicao.X, cobraParte.Posicao.Y + 1);
                    break;
                case Keys.Down:
                    posicao = new Vector2(cobraParte.Posicao.X, cobraParte.Posicao.Y - 1);
                    break;
                case Keys.Left:
                    posicao = new Vector2(cobraParte.Posicao.X + 1, cobraParte.Posicao.Y);
                    break;
                case Keys.Right:
                    posicao = new Vector2(cobraParte.Posicao.X - 1, cobraParte.Posicao.Y);
                    break;
            }
            var novaParte = new CobraParte((int)posicao.X, (int)posicao.Y, false, cobraParte.Textura) { UltimaCurva = cobraParte.UltimaCurva };
            Partes.Add(novaParte);
        }
    }
}
